home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / zcpp_jae.zip / TEMPLATE.C < prev    next >
C/C++ Source or Header  |  1992-07-14  |  18KB  |  570 lines

  1. /*
  2.  
  3.  
  4.  Copyright (C) 1990 Texas Instruments Incorporated.
  5.  
  6.  Permission is granted to any individual or institution to use, copy, modify,
  7.  and distribute this software, provided that this complete copyright and
  8.  permission notice is maintained, intact, in all copies and supporting
  9.  documentation.
  10.  
  11.  Texas Instruments Incorporated provides this software "as is" without
  12.  express or implied warranty.
  13.  
  14.  
  15.  *
  16.  * Edit history
  17.  * Created: LGO 30-Mar-89 -- Initial design and implementation.
  18.  * Updated: MJF 21-May-90 -- Added DECLARE_ONCE for CCC -X.
  19.  *
  20.  * Template, DECLARE and IMPLEMENT defmacro
  21.  *
  22.  * TO DO:
  23.  *    Generate a warning message when a template is encountered for a class
  24.  *    that has already had a DECLARE or IMPLEMENT run on it.
  25.  *
  26.  *    Scan for the "inline" keyword at the beginning of the "garbage pail"
  27.  *    template.
  28.  *
  29.  *     template needs a more robust heuristic for finding the class name
  30.  */
  31.  
  32. /*
  33. // C++ paramertized type macro support
  34. // This follows the conventions outlined in the 1988 USENIX C++ conference
  35. // paper titled "Parameterized Types for C++" by Bjarne Stroustrup
  36. //
  37. // To use, insert the following
  38. //    #pragma defmacro template <template>
  39. //
  40. //   template provides a specialized  way  of  defining  a  macro
  41. //   which supports parameterized classes.  A parameterized class
  42. //   is a class in which one or more pieces can  be  declared  at
  43. //   compile  time.  A typical example is a container class where
  44. //   the type of the contained object may change.  For example, a
  45. //   Vector  class would be paramertized for the type of the vec-
  46. //   tor elements.
  47.  
  48. //   Templates are expanded in two parts:  the  declarative  part
  49. //   needed  by  every  program file which uses the parameterized
  50. //   class, and the implementation part which needs  to  be  com-
  51. //   piled  once  for  the  class.   The  DECLARE macro expands a
  52. //   template's declarative part, and the IMPLEMENT macro expands
  53. //   a template's implementation part.
  54. //
  55. //   There are 3 kinds of template:
  56. //
  57. //   template<parms> class NAME { class_description };
  58. //        Defines a  template  the  declaration  of  class  NAME.
  59. //        PARAMETERS is:
  60. //           parms ::= type name [, parms]
  61. //        where type is ignored (its included for  AT&T  compata-
  62. //        bility)  and  name  is  the name of the parameter which
  63. //        will be substituted when the template is expanded  (Its
  64. //        like a macro argument in a #define).
  65. //
  66. //   template<parms> NAME result_type NAME<parms>::function { ... };
  67. //        Defines  a  method  for  the implementation of the NAME
  68. //        class.
  69. //
  70. //   template<class ARG> NAME inline rtype NAME<parms>::func { ... };
  71. //        Defines  an  inline  method  for the declaration of the
  72. //        NAME class.
  73. //
  74. //   template<class ARG> NAME {anything};
  75. //        This form is used to  define  anything  else  you  want
  76. //        associated with a template.  Use this form for defining
  77. //        typedef's or overloaded friend functions.  When this is
  78. //        found  before  the class template, the contents will be
  79. //        expanded before the class declaration.   When  this  is
  80. //
  81. // Example:
  82. //    template<class T> Vector {
  83. //    typedef Boolean (*Compare) (T&, T&);
  84. //    };
  85. //
  86. //    template<class T> class Vector {
  87. //        T* v;
  88. //        int sz;
  89. //    public:
  90. //        Vector<T>(int);
  91. //        T& operator[](int);
  92. //        T& elem(int i) { return v[i]; }
  93. //        // ...
  94. //    };
  95. //
  96. //    template<class T> Vector
  97. //    T& vector<T>::operator[](int i)
  98. //    {
  99. //        if (i<0 || sz<=i) error("vector: range error");
  100. //        return v[i];
  101. //    }
  102. //    vector<T>(size)
  103. //    {
  104. //        v = malloc(size);
  105. //    }
  106. //    // more method definitions
  107. //    ; // semicolon terminates
  108. //
  109. //    DECLARE Vector<char*>;   // create definitions for a vector of strings
  110. //    IMPLEMENT Vector<char*>; // generate code to support  vector of strings
  111. //    vector<char*> vs(30);     // declare a vector of 30 strings
  112. //
  113. */
  114.  
  115. #include "cppdef.h" /* added to fix #line for DOS <jae> */
  116.  
  117. #include "defmacio.h"
  118.  
  119. /* maximum number of template parameters */
  120. #define max_parms 32
  121. /* token buffer size */
  122. #define BSIZE 512
  123.  
  124. typedef enum { class_template,
  125.            declare_template,
  126.            implement_template } template_type;
  127.  
  128. typedef struct Template {
  129.   struct Template* next;    /* Next template or NULL */
  130.   template_type type;        /* type of template */
  131.   char** args;            /* argument names */
  132.   char* body;            /* program text */
  133.   int line;            /* Line number */
  134.   char* file;            /* file name */
  135. } TEMPLATE;
  136.  
  137. struct Temp_Head { TEMPLATE* head;      /* First template */
  138.            TEMPLATE* tail;  /* Last template */
  139.            int nparms;        /* Number of parameters */
  140.          };
  141.  
  142. static struct Hash_Table* template_table; /* Template hash table */
  143.  
  144. static char* name_n = NULL;    /* Name of current implementation */
  145.  
  146. TEMPLATE* append_template(self, name, nparms, head)
  147.   char* self;
  148.   char* name;
  149.   int nparms;
  150.   TEMPLATE** head;
  151. {
  152.   TEMPLATE* templ = (TEMPLATE*) getmem(sizeof(TEMPLATE));
  153.   struct Temp_Head* th;
  154.   if (template_table == NULL)
  155.     template_table = init_Hash_Table();
  156.   th = get_hash(template_table, name);
  157.   if (th == NULL) {              /* New template name, add head */
  158.     th = (struct Temp_Head *) getmem(sizeof(struct Temp_Head));
  159.     put_hash(template_table, savestring(name), th);
  160.     th->head = templ;
  161.     th->nparms = nparms;
  162.   } else {                  /* Else Old template */
  163.     th->tail->next = templ;          /* Link new template after last */
  164.     if (nparms != nparms) {          /* Check # parms */
  165.       fprintf(stderr, "%s: %s wrong number of parameters, expected %d\n",
  166.           self, name, nparms);
  167.       return NULL;
  168.     }
  169.   }
  170.   th->tail = templ;              /* New template is the last */
  171.   templ->next = NULL;
  172.   if(head != NULL) *head = th->head;      /* Return head when requested */
  173.   return templ;                  /* Return new template struct */
  174. }
  175.  
  176. /*
  177.  * Gather up the parameters
  178.  */
  179. static char** template_parms(self, nparmsp, is_template)
  180.   char* self;            /* Macro name */
  181.   Boolean is_template;        /* True when template, else implement */
  182.   int* nparmsp;            /* Place to return parameter count */
  183. {
  184.   char c;            /* Current character */
  185.   char buff[BSIZE];        /* character buffer */
  186.   char* parms[max_parms];    /* vector of parameters */
  187.   int nparms = 0;        /* number of parameters */
  188.  
  189.   while (TRUE) {
  190.     if (is_template && copytoken(buff) == NULL) /* throw out the type */
  191.       return NULL;
  192.     c = skip_blanks();
  193.     if (c == '*') c = skip_blanks();      /* Allow * after type */
  194.     if(!isalnum(c) && c != '"') {
  195.       fprintf(stderr,
  196.      "%s: Syntax error, strange character after parameter type %s: '%c'\n",
  197.      self, buff, c);
  198.       return NULL;
  199.     }
  200.     unget();
  201.     parms[nparms++] = scan_token(",>"); /* get a parameter */
  202.     c = skip_blanks();
  203.     if (c == '>') break;
  204.     if (c != ',') {
  205.       fprintf(stderr, "%s: Syntax error, '%c' instead of comma after parameter %s\n",
  206.           self, c, parms[nparms-1]);
  207.       return NULL;
  208.     }
  209.     if(nparms >= max_parms) {
  210.       fprintf(stderr, "%s: More than %d parameters\n", self, max_parms);
  211.       return NULL;
  212.     }
  213.   }
  214.   { char** result = (char**) getmem(sizeof(char*) * (nparms+1));
  215.     result[nparms] = NULL;
  216.     if(nparmsp != NULL) *nparmsp = nparms;
  217.     while(--nparms>=0) result[nparms] = parms[nparms];
  218.     return result;
  219.   }
  220. }
  221.  
  222. /*
  223.  * Handle the declare translation
  224.  */
  225. enum Do_What { do_declare, do_implement, do_implement_n };
  226.  
  227. static int declare_implement (do_what, do_line)
  228.    enum Do_What do_what;      /* What to do */
  229.    Boolean do_line;          /* When true, use #line */
  230. {
  231.   extern void macro_substitute(/* char* body, int nparm,
  232.                   char** parnames, char** parvalues */);
  233.   char c;            /* current character */
  234.   char buff[BSIZE];            /* character buffer */
  235.   char* name;            /* class name */
  236.   char* self;            /* macro name */
  237.   char** parms;            /* Buffer for parameters */
  238.   char** parmp;
  239.   int nparms;            /* Number of parameters */
  240.   int n;                /* Template number to process */
  241.  
  242.   if (copytoken(buff) == NULL)    /* get the macro name */
  243.     return 1;
  244.   self = savestring(buff);
  245.   if (do_what == do_implement_n) {
  246.     if (copytoken(buff) == NULL)    /* get the template number */
  247.       return 1;
  248.     n = atoi(buff);
  249.   }
  250.   if (copytoken(buff) == NULL)    /* get the class name */
  251.     return 1;
  252.   name = savestring(buff);
  253.   if(template_table == NULL) {
  254.     fprintf(stderr, "%s: Template for %s isn't defined\n", self, name);
  255.     return 1;
  256.   }
  257.   /*
  258.    * Templates sometimes contain IMPLEMENT statements.  This fouls
  259.    * up the implement_n mechanism, because a whole class will get
  260.    * implemented on one iteration.  To stop this, we record the
  261.    * name of the top-level implementation, and ignore any nested ones.
  262.    */
  263.   switch (do_what) {
  264.   case do_implement_n:
  265.     name_n = name; break;
  266.   case do_implement:
  267.     if (name_n != NULL && strcmp(name, name_n) != 0) {
  268.       /* Ignore nested IMPLEMENT */
  269.       fprintf(stderr, "Skipping IMPLEMENT %s\n", name); /* DEBUG */
  270.       return 0;
  271.     }
  272.   } /* end case */
  273.   /*
  274.    * Gather up the parameters
  275.    */
  276.   c = skip_blanks();
  277.   if (c != '<') {
  278.     fprintf(stderr, "%s: Syntax error, missing < after %s %s\n",
  279.         self, self, name);
  280.     return 1;
  281.   }
  282.   if ((parms = template_parms(self, &nparms, NULL)) == NULL)
  283.     return 1;
  284.   /*
  285.    * insert typedef's for pointer types
  286.    * (this is a work around for a cfront 1.2 bug)
  287.    */
  288.   for (parmp = parms; *parmp != NULL; parmp++) {
  289.     char* pname = *parmp;
  290.     char* ptype = pname;
  291.     int last = strlen(pname)-1;
  292.     if (pname[last] == '*') {
  293.       ptype = savestring(pname);
  294.       if(parmstring(ptype) != 0) return 1;
  295.       *parmp = ptype;
  296.       if (do_what == do_declare) {
  297.     sprintf(buff, "\n#ifndef %s_defined\n", ptype); puts(buff);
  298.     sprintf(buff, "#define %s_defined 1\n", ptype); puts(buff);
  299.     sprintf(buff, "typedef %s %s;\n", pname, ptype); puts(buff);
  300.     puts("#endif\n");
  301.       }
  302.     } /* end if a pointer parameter */
  303.   } /* end while for all parms */
  304.   { TEMPLATE* templ;
  305.     struct Temp_Head* th = get_hash(template_table, name);
  306.     if(th == NULL) {
  307.       fprintf(stderr, "%s: Template %s isn't defined\n", self, name);
  308.       return 1;
  309.     }
  310.     for(templ = th->head; templ != NULL; templ = templ->next) {
  311.       switch (do_what) {
  312.       case do_declare:   if(templ->type == implement_template) continue; break;
  313.       case do_implement: if(templ->type != implement_template) continue; break;
  314.       case do_implement_n:
  315.     if(templ->type != implement_template) continue;
  316.     if (n < 0) return 0;
  317.     if (n-- > 0) continue;
  318.     /* else fall through to implement template n */
  319.       }
  320.       if (do_line) {
  321.     char* bodyp = templ->body;
  322.     int newline = 0;
  323.         /*  Check for space at beginning of body */
  324.     for(; isspace(*bodyp); bodyp++)
  325.       if(*bodyp == '\n') {
  326.         newline = 1;
  327.         break;
  328.       }
  329.     sprintf(buff, "\n#line %d \"%s\"", newline + templ->line,
  330.             ESCNAME(templ->file));
  331.     puts(buff);
  332.     if(!newline) putchar('\n');
  333.       }
  334.       macro_substitute(templ->body, nparms, templ->args, parms);
  335.     }
  336.   }
  337.   if (do_what == do_implement_n && n >= 0) {
  338.     puts("\nBarf\n**** Template number too large ****\n");
  339.     fprintf(stderr, "Last Implementation\n");
  340.     exit(2);
  341.   }
  342.  
  343.  
  344. /*
  345.  *  help user do a declare only once in each file
  346.  *  by defining a variable (used by declare_once defmacro for CCC -X)
  347.  */
  348.   if (do_what == do_declare) {   
  349.     char ptype[512]; 
  350.     strcpy(ptype,name);
  351.     strcat(ptype,"<");
  352.     parmp = parms;
  353.     strcat(ptype,*parmp);
  354.     parmp++;
  355.     while (*parmp != NULL) {
  356.       strcat (ptype,",");
  357.       strcat (ptype,*parmp);
  358.       parmp++;
  359.     }
  360.     strcat(ptype,">");
  361.     parmstring(ptype);
  362.     sprintf(buff, "\n#ifndef %s_declared\n", ptype);  puts(buff);
  363.     sprintf(buff, "#define %s_declared 1\n", ptype); puts(buff);
  364.     puts("#endif\n");
  365.   }
  366.  
  367.   /*
  368.    * Invoke the hook macros
  369.    */
  370.   if(do_what == do_declare) {
  371.     puts("\n#ifdef DECLARE_HOOK");
  372.     puts("\nDECLARE_HOOK(");
  373.   } else {
  374.     puts("\n#ifdef IMPLEMENT_HOOK");
  375.     puts("\nIMPLEMENT_HOOK(");
  376.   }
  377.   puts(name);
  378.   putchar('<');
  379.   for (parmp = parms; *parmp != NULL;) {
  380.     puts(*parmp);
  381.     if (*++parmp == NULL) break;
  382.     puts(" ,");
  383.   }
  384.   puts(">)\n#endif\n");
  385.   return 0;
  386. }
  387.  
  388. /*
  389.  * Handle the template translation
  390.  */
  391. int template (argc, argv) 
  392.   int argc;
  393.   char** argv;
  394. {
  395.   char c;            /* current character */
  396.   char buff[BSIZE];        /* character buffer */
  397.   char* self;            /* our name */
  398.   char** parms;            /* template parameters */
  399.   int nparms;            /* parameter count */
  400.   char* file = savestring(current_file);
  401.   if(copytoken(buff) == NULL)    /* Grab macro name */
  402.     return 1;
  403.   self = savestring(buff);
  404.   c = skip_blanks();
  405.   if (c != '<') {
  406.     fprintf(stderr, "%s: Syntax error, missing < after %s\n", self, self);
  407.     return(1);
  408.   }
  409.   /*
  410.    * Get the parameters
  411.    */
  412.   if ((parms = template_parms(self, &nparms, TRUE)) == NULL)
  413.     return 1;
  414.   /*
  415.    * Find out what kind of template
  416.    */
  417.   { TEMPLATE* templ;        /* new template */
  418.     STRING body = (scan_start(), work_string);
  419.     append_blanks(body);
  420.     unget();
  421.     if(copytoken(buff) == NULL)    /* Get first token after template parms */
  422.       return 1;
  423.     append_STRING(body, buff);
  424.     c = append_blanks(body);
  425.     unget();
  426.     /*
  427.      * class template
  428.      */
  429.     if(!strcmp(buff, "class")) {
  430.       extern int parmtype();
  431.       char* name;
  432.       if (copytoken(buff) == NULL) /* token after class is the class name */
  433.     return 1;
  434.       name = savestring(buff);
  435.       templ = append_template(self, buff, nparms, NULL);
  436.       if (templ == NULL) return 1;
  437.       append_STRING(body, buff);
  438.       while ((c = getchar()) != EOF) append_char(body, c);
  439.       append_char(body, ';');
  440.       append_char(body, EOS);
  441.       templ->type = class_template;
  442.       templ->args = parms;
  443.       templ->body = savestring(body->buff);
  444.       templ->line = current_line;
  445.       templ->file = file;
  446.       /* define a parmtype defmacro for this class name */
  447.       new_defmacro(name, FALSE, FALSE, '>', '<', parmtype, "parmtype", NULL);
  448.     } else {
  449.       /*
  450.        * auxillary template
  451.        */
  452.       if (c == '{') {            /* An auxillary declaration template */
  453.     TEMPLATE* t;
  454.     { char* buffp = body->buff; /* Update line count */
  455.       while (buffp < body->buffp)
  456.         if(*buffp++ == '\n') current_line++;
  457.     }
  458.     body->buffp = body->buff; /* Empty out body */
  459.     { char p;          /* Copy everything except surrounding {} */
  460.       getchar();
  461.       for (p = getchar(); (c = getchar()) != EOF; p = c)
  462.         append_char(body, p);
  463.       append_char(body, EOS);
  464.     }
  465.     templ = append_template(self, buff, nparms, &t);
  466.     if (templ == NULL) return 1;
  467.     templ->args = parms;
  468.     templ->body = savestring(body->buff);
  469.     templ->line = current_line;
  470.     templ->file = file;
  471.     templ->type = declare_template;      /* Determine template type */
  472.     for (; t != NULL; t = t->next)
  473.       if(t->type == class_template) { /* If after a class template */
  474.         templ->type = implement_template;
  475.         break;
  476.       }
  477.       }
  478.       /*
  479.        * function template
  480.        */
  481.       else {
  482.     template_type type = implement_template;
  483.     if (!strcmp(buff, "inline")) type = declare_template;
  484.     while ((c = getchar()) != EOF) append_char(body, c);
  485.     append_char(body, EOS);
  486.     { char* bodyp = body->buff;
  487.       char* startname;
  488.       char* endname;
  489.       do {                  /* Search for name< */
  490.         while((c = *bodyp++) != EOS && c != '<');
  491.         if(c == EOS) {
  492.           fprintf(stderr, "Can't find template class\n");
  493.           return 1;
  494.         }
  495.                       /* Scan backwards for name */
  496.         for (endname = bodyp-1; isspace(*(endname-1)); endname--);        
  497.         for (startname = endname; startname>body->buff; startname--) {
  498.           c = *(startname-1);
  499.           if(!isalnum(c) && c!='_' && c!='$') break;
  500.         }
  501.         strncpy(buff, startname, endname-startname);
  502.         buff[endname-startname] = EOS;
  503.                       /* Ensure token after < is parm */
  504.         while(isspace(*bodyp)) bodyp++;
  505.       } while (strncmp(bodyp, *parms, strlen(*parms)));
  506.       templ = append_template(self, buff, nparms, NULL);
  507.       if (templ == NULL) return 1;
  508.       templ->type = type;
  509.       templ->args = parms;
  510.       templ->body = savestring(body->buff);
  511.       templ->line = current_line;
  512.       templ->file = file;
  513.     }
  514.       }
  515.     }
  516.   }
  517.   free(self);
  518.   return 0;
  519. }
  520.  
  521. int declare (argc, argv)
  522.   int argc;
  523.   char** argv;
  524. {
  525.   return declare_implement(do_declare, argc>1);
  526. }    
  527.  
  528. int implement (argc, argv)
  529.   int argc;
  530.   char** argv;
  531. {
  532.   if (argc > 2 && name_n == NULL) name_n = savestring(argv[2]);
  533.   return declare_implement(do_implement, argc>1);
  534. }    
  535.  
  536. /*
  537.  * Implement the Nth template
  538.  *   Example:
  539.  *      IMPLEMENT 3 Vector<char*>
  540.  */
  541. int implement_n (argc, argv)
  542.   int argc;
  543.   char** argv;
  544. {
  545.   return declare_implement(do_implement_n, argc>1);
  546. }    
  547.  
  548. int declare_once (argc, argv)
  549.   int argc;
  550.   char** argv;
  551. {
  552.   char buff[BSIZE];            /* character buffer */
  553.   char* self;            /* macro name */
  554.   char* parmtype;        /* parm type name */
  555.   char* parmname;
  556.  
  557.   if (copytoken(buff) == NULL)    /* get the macro name */
  558.     return 1;
  559.   self = savestring(buff);
  560.  
  561.   parmtype = scan_token(">"); /* get full parameters type name */
  562.   parmname = savestring(parmtype);
  563.   if(parmstring(parmtype) != 0) return 1;
  564.   sprintf(buff, "\n#ifndef %s_declared\n", parmtype); puts(buff);
  565.   sprintf(buff, "#define %s_declared 1\n", parmtype); puts(buff);
  566.   sprintf(buff, "DECLARE %s\n", parmname); puts(buff);
  567.   puts("#endif\n");
  568.   return 0;
  569. }    
  570.